package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    private ApArticleMapper articleMapper;

    @Autowired
    private IWemediaClient channelFeginClient;

    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
     * 计算热点文章的业务方法
     * 是否有返回值,没有
     * 是否有参数，
     * 没有，
     * 该业务方法是要被定时任务自动调用的
     */
    @Override
    public void computeHotArticle() {
        //1.查询前五天的文章列表
        List<ApArticle> articleList=last5DayArticleList();

        //2.计算分值
        List<HotArticleVo> articleScoreList= jisuanArticleScore(articleList);

        //3.计算分值之后的文章列表存储到redis中
        cacheArticleToRedis(articleScoreList);
    }

    /**
     * 抽取的第四个方法，缓存数据到redis
     * @param articleScoreList
     */
    private void cacheArticleToRedis(List<HotArticleVo> articleScoreList) {
        //1.根据每个频道来缓存
        //1.1 获取所有的频道列表
        ResponseResult<List<WmChannel>> responseResult = channelFeginClient.list();
        List<WmChannel> channels = responseResult.getData();
        for (WmChannel channel : channels) {
            //获取每一个频道下的所有的文章列表
            List<HotArticleVo> channelArticleList = articleScoreList.stream().filter(hotArticleVo -> hotArticleVo.getChannelId().equals(channel.getId())).collect(Collectors.toList());
            cacheToRedis(channelArticleList,"hot_article_first_page_"+ channel.getId());
        }
        //2.根据推荐来缓存
        cacheToRedis(articleScoreList,"hot_article_first_page"+"__all__");
    }

    private void cacheToRedis( List<HotArticleVo> articleList,String key) {
        //按照分值排序+取出前三十条分值最高的文章
        articleList = articleList.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30)
                .collect(Collectors.toList());
        //存数据到redis中
        redisTemplate.opsForValue().set(key, JSON.toJSONString(articleList));
    }

    /**
     * 第二个抽取的方法，计算每一篇的文章分值
     * @param articleList
     * @return
     */
    private List<HotArticleVo> jisuanArticleScore(List<ApArticle> articleList) {

        List<HotArticleVo> articleScoreList=new ArrayList<>();

        //1.判断非空
        if(articleList==null || articleList.size()<=0){
            return null;
        }
        //2.计算分值，每一篇文章
        for (ApArticle apArticle : articleList) {
            HotArticleVo vo=new HotArticleVo();
            BeanUtils.copyProperties(apArticle,vo);
            //调用计算分值
            Integer score=computeArticleScore(apArticle);
            vo.setScore(score);
            articleScoreList.add(vo);
        }
        return articleScoreList;
    }

    /**
     * 抽取的第三个方法，计算每一篇文章的分值
     * @return
     */
    private Integer computeArticleScore(ApArticle apArticle) {
        Integer score=0;
        if(apArticle.getLikes()!=null){
            score+=apArticle.getLikes()*3;
        }
        if(apArticle.getViews()!=null){
            score+=apArticle.getViews();
        }
        if(apArticle.getComment()!=null){
            score+=apArticle.getComment()*5;
        }
        if(apArticle.getCollection()!=null){
            score+=apArticle.getCollection()*8;
        }
        return score;
    }

    /**
     * 抽取的第一个方法，获取前五天的文章列表
     * @return
     */
    private List<ApArticle> last5DayArticleList() {
        //2.获取前五天的日期
        Calendar calendar=Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH,-5);
        Date before5Day=calendar.getTime();

        //1.调用mapper接口
        List<ApArticle> before5DayArtileList = articleMapper.findArticleListByLast5days(before5Day);
        return before5DayArtileList;
    }
}